import {FormControl} from '@angular/forms';

/**
 * @author leihfei
 * @date 2019-04-01
 * @description 公共校验器
 */
export class SelfValidators {
    static code = '';

    /**
     * 4到16位（字母，数字，下划线，减号）
     */
    static baseString(control: FormControl): any {
        if (control.value) {
            const pattern = /^[a-zA-Z0-9_-]{2,45}$/;
            const valid = pattern.test(control.value);
            return valid ? null : {baseString: {errorMsg: '字母，数字，下划线，减号等，至少两位字符'}};
        }
    }

   /** 网址校验
    * @author csw
    * @description:匹配正规的各种网址
    * @date 2020-10-15 16:31:11
    */
    static isUrl(control: FormControl): any {
        const strRegex = /^(([hH][tT]{2}[pP]?|[hH][tT]{2}[pP][sS]|ftp|news):\/\/|www\.)?([0-9]|[a-z]([a-z0-9\-]*[\.。])+([a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel)|(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&]*)?)?(#[a-z][a-z0-9_]*)?$/;
        const valid = strRegex.test(control.value);
        return valid ? null : {isUrl: {errorMsg: '网址格式不正确'}};
    }

    /**
     * 严格密码格式：
     * 6到16位，包括至少1个大写字母，1个小写字母，1个数字，1个特殊字符
     */
    static strictPassword(control: FormControl): any {
        if (control.value == null || control.value === undefined || control.value === '') {
            return null;
        } else {
            const pattern = /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$/;
            const valid = pattern.test(control.value);
            return valid ? null : {strictPassword: {errorMsg: '最少6位，包括至少1个大写字母，1个小写字母，1个数字，1个特殊字符'}};
        }
    }

    /**
     * 一般密码格式：
     * '6到16位，表示是字母或数字'
     */
    static commPassword(control: FormControl): any {
        if (control.value == null || control.value === undefined || control.value === '') {
            return null;
        } else {
            const pattern = /^[0-9a-zA-Z]{6,16}$/;
            const valid = pattern.test(control.value);
            return valid ? null : {commPassword: {errorMsg: '6到16位，字母或数字不能包含特殊字符'}};
        }
    }

    /**
     * 一般密码格式：
     * '6到16位，表示必须是字母和数字组合'
     */
    static letterNumberPwd(control: FormControl): any {
        if (control.value == null || control.value === undefined || control.value === '') {
            return null;
        } else {

            const pattern = /^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,20}$/;
            // const pattern = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$/;
            const valid = pattern.test(control.value);
            return valid ? null : {letterNumberPwd: {errorMsg: '6到16位，必须带字母和数字的组合'}};
        }
    }

    /**
     * 中文
     */
    static chineseValidator(control: FormControl): any {
        if (control.value == null || control.value === undefined || control.value === '') {
            return null;
        } else {
            const pattern = /[\u4e00-\u9fa5]+$/;
            const valid = pattern.test(control.value);
            return valid ? null : {chineseValidator: {errorMsg: '请输入中文'}};
        }
    }

    /**
     * 只验证中文(其他不管)
     */
    static chineseOnlyValidator(control: FormControl): any {
        if (control.value === null || control.value === undefined || control.value === '') {
            return null;
        }
        const pattern = /[\u4e00-\u9fa5]+$/;
        const valid = pattern.test(control.value);
        return valid ? null : {chineseOnlyValidator: {errorMsg: '请输入中文'}};
    }

    /**
     * 校验是否包含空格
     */
    static checkTextSpace(control: FormControl): any {
        const pattern = /(\s+)|(\s+$)/g;
        const valid = !pattern.test(control.value);
        return valid ? null : {checkTextSpace: {errorMsg: '请去掉空格!'}};
    }

    /**
     * 电子邮箱
     */
    static emailValidator(control: FormControl): any {
        if (control.value) {
            const pattern = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
            const valid = pattern.test(control.value);
            return valid ? null : {emailValidator: {errorMsg: '请输入正确的邮箱'}};
        }
    }

    /**
     * 任意字符密码
     */
    static anyPassword(control: FormControl): any {
        let valid = false;
        if (control.value === null || control.value === 'null' || control.value === undefined || control.value === 'undefined') {
            return null;
        } else if (control.value['length'] > 5 && control.value['length'] < 17) {
            valid = true;
        }
        return valid ? null : {anyPassword: {errorMsg: '请输入正确的密码，长度为6到16位'}};
    }

    /**
     * 正整数
     */
    static postitiveValidator(control: FormControl): any {
        if (control.value == null || control.value === '' || control.value === undefined) {
            return null;
        }
        const pattern = /^[1-9][0-9]*$/;
        const valid = pattern.test(control.value);
        return valid ? null : {postitiveValidator: {errorMsg: '请输入正整数'}};
    }

    /**
     * 金额
     */
    static moneyValidator(control: FormControl): any {
        if (control.value == null || control.value === '' || control.value === undefined) {
            return null;
        }
        const pattern = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/;
        const valid = pattern.test(control.value);
        return valid ? null : {moneyValidator: {errorMsg: '金额形式不正确'}};
    }

    /**
     * 负整数
     */
    static negativeValidator(control: FormControl): any {
        const pattern = /^-[1-9]\d*|0$/;
        const valid = pattern.test(control.value);
        return valid ? null : {negative: {errorMsg: '请输入负整数'}};
    }


    /**
     * 验证只能输入字符和数字
     */
    static chrnum(control: FormControl): any {
        const chrnum = /^([a-zA-Z])+([0-9]+)$/;
        const valid = chrnum.test(control.value);
        return valid ? null : {chrnum: {errorMsg: '只能输入数字和字母(字符A-Z, a-z, 0-9)'}};
    }

    /**
     * 只能输入字母
     */
    static nameCheck(control: FormControl): any {
        const pattern = /^([a-zA-Z]+)$/;
        const valid = pattern.test(control.value);
        return valid ? null : {nameCheck: {errorMsg: '只能输入字母'}};
    }

    /**
     * 字符验证
     */
    static stringCheck(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        const pattern = /^[a-zA-Z0-9\u4e00-\u9fa5-_]{2,60}$/gi;
        const valid = pattern.test(control.value);
        return valid ? null : {stringCheck: {errorMsg: '只能包括中文字、英文字母、数字和下划线'}};
    }


    /**
     * 手机号
     */
    static mobileValidator(control: FormControl): any {
        if (control.value == null || control.value === '') {
            return null;
        }
        const partten = /^1[3|4|5|7|8|1|2]\d{9}$/;
        const valid = partten.test(control.value);
        return valid ? null : {mobileValidator: {errorMsg: '手机号格式不正确'}};
    }

    /**
     * 电话号码验证
     */
    static isTel(control: FormControl): any {
        if (control.value === null || control.value === '') {
            return null;
        }
        const pattern = /^\d{3,4}-?\d{7,9}$/; // 电话号码格式010-12345678
        const valid = pattern.test(control.value);
        return valid ? null : {isTel: {errorMsg: '请正确填写您的电话号码'}};
    }

    /**
     * 请正确填写您的联系电话与固定电话
     */
    static isPhone(control: FormControl): any {
        if (control.value) {
            const pattern = /^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0-9]))\d{8}$|^0\d{2,3}-?\d{7,8}$/;
            const valid = pattern.test(control.value);
            return valid ? null : {isPhone: {errorMsg: '请正确填写您的联系电话'}};
        }
    }

    /**
     * 车牌号校验
     */
    static carNumber(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        const pattern = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/;
        const valid = pattern.test(control.value);
        return valid ? null : {carNumber: {errorMsg: '请正确填写车牌号'}};
    }

    /**
     * 校验是都是护照
     */
    static isIdCards(control: any): any {
        if (control === null || control === '') {
            return null;
        }
        // 在校验是都是护照

        const valid = new IdCardNoUtil().checkIdCardNo(control);
        return valid ? null : '身份证号错误(x大写)';
    }

    /**
     *  18位身份证号码
     */
    static isIdCardNo(control: FormControl): any {
        if (control.value === null || control.value === '') {
            return null;
        }
        // 在校验是都是护照

        const valid = new IdCardNoUtil().checkIdCardNo(control.value);
        return valid ? null : {isIdCardNo: {errorMsg: '请输入正确的身份证号(x大写)'}};
    }


    /**
     *  18位身份证号码或护照
     */
    static isIdCardNoOrHZ(control: FormControl): any {
        if (control.value === null || control.value === '') {
            return null;
        }
        // 在校验是都是护照
        const check = /^[a-zA-Z0-9]{8}$/.test(control.value);
        const check2 = /^[a-zA-Z]{8}$/.test(control.value);

        const valid = new IdCardNoUtil().checkIdCardNo(control.value);

        return (check || check2 || valid) ? null : {isIdCardNoOrHZ: {errorMsg: '请输入正确的证件号(x大写)'}};
    }

    /**
     * 验证验证码
     */
    static checkCode(control: FormControl): any {

        const re = (SelfValidators.code.toUpperCase() === control.value.toUpperCase()) ? null : {inputCode: {errorMsg: '请输入正确的验证码'}};
        return re;
    }

    /**
     *  邮政编码
     * @param control 值
     * @returns  返回值
     */
    static isZipCode(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        const pattern = /^[0-9]{6}$/;
        const valid = pattern.test(control.value);
        return valid ? null : {isZipCode: {errorMsg: '请正确填写您的邮政编码'}};
    }

    /**
     *  IP地址
     * @param control 值
     * @returns 返回值
     */
    static ipAddressCode(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        const pattern = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/;
        const valid = pattern.test(control.value);
        return valid ? null : {ipAddressCode: {errorMsg: '请正确填写您的IP地址'}};
    }

    /**
     * 端口号
     * @param control 值
     * @returns 返回值
     */
    static portCheck(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        const pattern = /^[1-9]\d*|0$/;
        const valid = pattern.test(control.value);
        return (valid && (control.value < 65537)) ? null : {portCheck: {errorMsg: '端口号输入异常(不能为负且最大值为65536)'}};
    }

    /**
     *  IP地址+端口号
     * @param control 值
     * @returns 返回值
     */
    static ipAddressPort(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        const pattern = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\:([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])$/;
        const valid = pattern.test(control.value);
        return valid ? null : {ipAddressPort: {errorMsg: '请正确填写您的IP地址'}};
    }

    /**
     * 校验浮点型数据，经纬度
     * @param control 值
     * @returns 返回值
     */
    static checkFloat(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        return SelfValidators.checkNumberFAD(control) ? null : {checkFloat: {errorMsg: '请输入正确的经纬度'}};
    }

    /**
     * 校验数值长度为1
     * @param control 值
     * @returns 返回值
     */
    static checkNumberLength(control: FormControl): any {
        const data = control.value;
        if (data == null) {
            return null;
        } else {
            if (data < 100) {
                return null;
            } else {
                return {checkNumberLength: {errorMsg: '输入小于100的数'}};
            }
        }
    }

    /**
     * 检查小数点类型的数据
     * @param control 值
     * @returns 返回值
     */
    static checkNumber(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        const pattern = /^[0-9]+(.[0-9]{1,2})?$/;
        const valid = pattern.test(control.value);
        return valid ? null : {checkNumber: {errorMsg: '请输入正确的小数点类型数据'}};
    }

    /**
     * 数字字母特殊字符
     * @param control 值
     * @returns 返回值
     */
    static userNameCheck(control: FormControl): any {
        if (control.value == null) {
            return null;
        }
        const pattern = /^(?=.*[a-zA-Z\d])[!-~]{6,20}$/;
        const valid = pattern.test(control.value);
        return valid ? null : {userNameCheck: {errorMsg: '6-20位数字字母特殊字符!'}};
    }


    private static checkNumberFAD(control: FormControl): boolean {
        let valid = false;
        for (let i = 0; i < control.value.length; i++) {
            const pattern = /^[1-9]\d*|0|\.$/;
            valid = pattern.test(control.value[i]);
            if (!valid) {
                break;
            }
        }
        return valid;
    }
}


/**
 * 身份证校验器
 */
export class IdCardNoUtil {

    provinceAndCitys = {
        11: '北京',
        12: '天津',
        13: '河北',
        14: '山西',
        15: '内蒙古',
        21: '辽宁',
        22: '吉林',
        23: '黑龙江',
        31: '上海',
        32: '江苏',
        33: '浙江',
        34: '安徽',
        35: '福建',
        36: '江西',
        37: '山东',
        41: '河南',
        42: '湖北',
        43: '湖南',
        44: '广东',
        45: '广西',
        46: '海南',
        50: '重庆',
        51: '四川',
        52: '贵州',
        53: '云南',
        54: '西藏',
        61: '陕西',
        62: '甘肃',
        63: '青海',
        64: '宁夏',
        65: '新疆',
        71: '台湾',
        81: '香港',
        82: '澳门',
        91: '国外'
    };
    powers = ['7', '9', '10', '5', '8', '4', '2', '1', '6', '3', '7', '9', '10', '5', '8', '4', '2'];
    parityBit = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
    genders = {male: '男', female: '女'};

    private checkAddressCode(addressCode) {
        const check = /^[1-9]\d{5}$/.test(addressCode);
        if (!check) {
            return false;
        }
        if (this.provinceAndCitys[addressCode.substring(0, 2) as number]) {
            return true;
        } else {
            return false;
        }
    }

    private checkBirthDayCode(birDayCode) {
        const check = /^[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))$/.test(birDayCode);
        if (!check) {
            return false;
        }
        const yyyy = parseInt(birDayCode.substring(0, 4), 10);
        const mm = parseInt(birDayCode.substring(4, 6), 10);
        const dd = parseInt(birDayCode.substring(6), 10);
        const xdata = new Date(yyyy, mm - 1, dd);
        if (xdata > new Date()) {
            return false; // 生日不能大于当前日期
        } else if ((xdata.getFullYear() === yyyy) && (xdata.getMonth() === mm - 1) && (xdata.getDate() === dd)) {
            return true;
        } else {
            return false;
        }
    }

    private getParityBit(idCardNo) {
        const id17 = idCardNo.substring(0, 17);

        let power = 0;
        for (let i = 0; i < 17; i++) {
            power += parseInt(id17.charAt(i), 10) * parseInt(this.powers[i], 10);
        }

        const mod = power % 11;
        return this.parityBit[mod];
    }

    private checkParityBit(idCardNo) {
        const parityBit = idCardNo.charAt(17).toUpperCase();
        if (this.getParityBit(idCardNo) === parityBit) {
            return true;
        } else {
            return false;
        }
    }

    public checkIdCardNo(idCardNo) {
        // 15位和18位身份证号码的基本校验
        const check = /^\d{15}|(\d{17}(x|X|\d))$/.test(idCardNo);
        if (!check) {
            return false;
        }
        // 判断长度为15位或18位
        if (idCardNo.length === 15) {
            return this.check15IdCardNo(idCardNo);
        } else if (idCardNo.length === 18) {
            return this.check18IdCardNo(idCardNo);
        } else {
            return false;
        }
    }

    // 校验15位的身份证号码
    private check15IdCardNo(idCardNo) {
        // 15位身份证号码的基本校验
        let check = /^[1-9]\d{7}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}$/.test(idCardNo);
        if (!check) {
            return false;
        }
        // 校验地址码
        const addressCode = idCardNo.substring(0, 6);
        check = this.checkAddressCode(addressCode);
        if (!check) {
            return false;
        }
        const birDayCode = '19' + idCardNo.substring(6, 12);
        // 校验日期码
        return this.checkBirthDayCode(birDayCode);
    }

    // 校验18位的身份证号码
    private check18IdCardNo(idCardNo) {
        // 18位身份证号码的基本格式校验
        let check = /^[1-9]\d{5}[1-9]\d{3}((0[1-9])|(1[0-2]))((0[1-9])|([1-2][0-9])|(3[0-1]))\d{3}(X|\d)$/.test(idCardNo);
        if (!check) {
            return false;
        }
        // 校验地址码
        const addressCode = idCardNo.substring(0, 6);
        check = this.checkAddressCode(addressCode);
        if (!check) {
            return false;
        }
        // 校验日期码
        const birDayCode = idCardNo.substring(6, 14);
        check = this.checkBirthDayCode(birDayCode);
        if (!check) {
            return false;
        }
        // 验证校检码
        return this.checkParityBit(idCardNo);
    }

    private formateDateCN(day) {
        const yyyy = day.substring(0, 4);
        const mm = day.substring(4, 6);
        const dd = day.substring(6);
        return yyyy + '-' + mm + '-' + dd;
    }

    // 获取信息
    private getIdCardInfo(idCardNo) {
        const idCardInfo = {
            gender: '', // 性别
            birthday: '' // 出生日期(yyyy-mm-dd)
        };
        if (idCardNo.length === 15) {
            const aday = '19' + idCardNo.substring(6, 12);
            idCardInfo.birthday = this.formateDateCN(aday);
            if (idCardNo.charAt(14) as number % 2 === 0) {
                idCardInfo.gender = this.genders.female;
            } else {
                idCardInfo.gender = this.genders.male;
            }
        } else if (idCardNo.length === 18) {
            const aday = idCardNo.substring(6, 14);
            idCardInfo.birthday = this.formateDateCN(aday);
            if (idCardNo.charAt(16) as number % 2 === 0) {
                idCardInfo.gender = this.genders.female;
            } else {
                idCardInfo.gender = this.genders.male;
            }

        }
        return idCardInfo;
    }

    private getId15(idCardNo) {
        if (idCardNo.length === 15) {
            return idCardNo;
        } else if (idCardNo.length === 18) {
            return idCardNo.substring(0, 6) + idCardNo.substring(8, 17);
        } else {
            return null;
        }
    }

    private getId18(idCardNo) {
        if (idCardNo.length === 15) {
            const id17 = idCardNo.substring(0, 6) + '19' + idCardNo.substring(6);
            const parityBit = this.getParityBit(id17);
            return id17 + parityBit;
        } else if (idCardNo.length === 18) {
            return idCardNo;
        } else {
            return null;
        }
    }

}

